package com.huatai.common.utils;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

public final class FileUtils {

	private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);

	private static final int BUFFER_SIZE = 1024 * 64; // 64K
	private static final int MAX_BUFFER_SIZE = 1024 * 1024; // 64K
	private static final int MIN_BUFFER_SIZE = 1024 * 8; // 64K

	// This is an utility class
	private FileUtils() {
	}

	public static void safeClose(Closeable stream) {
		try {
			stream.close();
		} catch (IOException e) {
			// ExceptionUtil.caught(e, "关闭流失败");
		}
	}

	private static byte[] createBuffer(int preferredSize) {
		if (preferredSize < 1) {
			preferredSize = BUFFER_SIZE;
		}
		if (preferredSize > MAX_BUFFER_SIZE) {
			preferredSize = MAX_BUFFER_SIZE;
		} else if (preferredSize < MIN_BUFFER_SIZE) {
			preferredSize = MIN_BUFFER_SIZE;
		}
		return new byte[preferredSize];
	}

	public static void copy(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = createBuffer(in.available());
		int read;
		while ((read = in.read(buffer)) != -1) {
			out.write(buffer, 0, read);
		}
	}

	public static String read(InputStream in) throws IOException {
		StringBuffer sb = new StringBuffer();
		byte[] buffer = createBuffer(in.available());
		try {
			int read;
			while ((read = in.read(buffer)) != -1) {
				sb.append(new String(buffer, 0, read));
			}
		} finally {
			in.close();
		}
		return sb.toString();
	}

	public static byte[] readBytes(URL url) throws IOException {
		return readBytes(url.openStream());
	}

	public static byte[] readBytes(InputStream in) throws IOException {
		byte[] buffer = createBuffer(in.available());
		int w = 0;
		try {
			int read = 0;
			int len;
			do {
				w += read;
				len = buffer.length - w;
				if (len <= 0) { // resize buffer
					byte[] b = new byte[buffer.length + BUFFER_SIZE];
					System.arraycopy(buffer, 0, b, 0, w);
					buffer = b;
					len = buffer.length - w;
				}
			} while ((read = in.read(buffer, w, len)) != -1);
		} finally {
			in.close();
		}
		if (buffer.length > w) { // compact buffer
			byte[] b = new byte[w];
			System.arraycopy(buffer, 0, b, 0, w);
			buffer = b;
		}
		return buffer;
	}

	public static String readFile(File file) throws IOException {
		return read(new FileInputStream(file));
	}

	public static List<String> readLines(File file) throws IOException {
		List<String> lines = new ArrayList<String>();
		BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
		String line;
		while ((line = reader.readLine()) != null) {
			lines.add(line);
		}
		return lines;
	}

	public static void writeLines(String dstDirectoryName, String fileName, List<String> lines) throws IOException {
		File dstDirectory = new File(dstDirectoryName);
		if (!dstDirectory.exists())
			dstDirectory.mkdirs();
		PrintWriter out = null;
		try {
			out = new PrintWriter(new FileOutputStream(dstDirectoryName + "/" + fileName));
			for (String line : lines) {
				out.println(line);
			}
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	public static void writeLines(File file, List<String> lines) throws IOException {
		PrintWriter out = null;
		try {
			if (!file.getParentFile().exists())
				file.getParentFile().mkdirs();
			out = new PrintWriter(new FileOutputStream(file));
			for (String line : lines) {
				out.println(line);
			}
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	public static byte[] readBytes(File file) throws IOException {
		return readBytes(new FileInputStream(file));
	}

	public static void writeFile(File file, byte[] buf) throws IOException {
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file);
			fos.write(buf);
		} finally {
			if (fos != null) {
				fos.close();
			}
		}
	}

	public static void writeFile(File file, String buf) throws IOException {
		writeFile(file, buf.getBytes());
	}

	public static void download(URL url, File file) throws IOException {
		InputStream in = url.openStream();
		OutputStream out = new FileOutputStream(file);
		try {
			copy(in, out);
		} finally {
			if (in != null) {
				in.close();
			}
			out.close();
		}
	}

	public static void deleteTree(File dir) {
		emptyDirectory(dir);
		dir.delete();
	}

	public static void emptyDirectory(File dir) {
		File[] files = dir.listFiles();
		if (files == null) {
			return;
		}
		int len = files.length;
		for (int i = 0; i < len; i++) {
			File file = files[i];
			if (file.isDirectory()) {
				deleteTree(file);
			} else {
				file.delete();
			}
		}
	}

	public static void copyToFile(InputStream in, File file) throws IOException {
		OutputStream out = null;
		try {
			out = new FileOutputStream(file);
			byte[] buffer = createBuffer(in.available());
			int read;
			while ((read = in.read(buffer)) != -1) {
				out.write(buffer, 0, read);
			}
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	public static void append(File src, File dst) throws IOException {
		append(src, dst, false);
	}

	public static void append(File src, File dst, boolean appendNewLine) throws IOException {
		InputStream in = null;
		try {
			in = new FileInputStream(src);
			append(in, dst, appendNewLine);
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	public static void append(InputStream in, File file) throws IOException {
		append(in, file, false);
	}

	public static void append(InputStream in, File file, boolean appendNewLine) throws IOException {
		OutputStream out = null;
		try {
			out = new BufferedOutputStream(new FileOutputStream(file, true));
			if (appendNewLine) {
				out.write(System.getProperty("line.separator").getBytes());
			}
			byte[] buffer = new byte[BUFFER_SIZE];
			int read;
			while ((read = in.read(buffer)) != -1) {
				out.write(buffer, 0, read);
			}
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * Copies source to destination. If source and destination are the same,
	 * does nothing. Both single files and directories are handled.
	 * 
	 * @param src
	 *            the source file or directory
	 * @param dst
	 *            the destination file or directory
	 * @throws IOException
	 */
	public static void copy(File src, File dst) throws IOException {
		if (src.equals(dst)) {
			return;
		}
		if (src.exists()) { // 既可以判断文件存在否，也可以判断文件夹存在否
			if (src.isFile()) {
				copyFile(src, dst);
			} else {
				copyTree(src, dst);
			}
		} else {
			logger.info("文件不存在：{}", src.getName());
		}

	}

	public static void copy(File[] src, File dstDirectory) throws IOException {
		for (File file : src) {
			copy(file, dstDirectory);
		}
	}

	public static void copyFile(File src, File dstDirectory) throws IOException {
		copyFile(src, dstDirectory, src.getName());
	}

	public static void copyFile(String srcDirectory, String dstDirectory, String fileName) throws IOException {
		File src = new File(srcDirectory + fileName);
		File dst = new File(dstDirectory);
		copyFile(src, dst, fileName);
	}

	public static void copyFile(File src, File dstDirectory, String fileName) throws IOException {
		if (!dstDirectory.exists())
			dstDirectory.mkdirs();
		FileInputStream in = null;
		FileOutputStream out = null;
		try {
			in = new FileInputStream(src);
			out = new FileOutputStream(new File(dstDirectory, fileName));
			copy(in, out);
		} catch (Exception e) {
			throw e;
		} finally {
			if (in != null)
				in.close();
			if (out != null)
				out.close();

		}
	}

	/**
	 * Copies recursively source to destination.
	 * <p>
	 * The source file is assumed to be a directory.
	 * 
	 * @param src
	 *            the source directory
	 * @param dst
	 *            the destination directory
	 * @throws IOException
	 */
	public static void copyTree(File src, File dst) throws IOException {
		if (src.isFile()) {
			copyFile(src, dst);
		} else if (src.isDirectory()) {
			if (dst.exists()) {
				dst = new File(dst, src.getName());
				dst.mkdir();
			} else { // alow renaming dest dir
				dst.mkdirs();
			}
			File[] files = src.listFiles();
			for (File file : files) {
				copyTree(file, dst);
			}
		}
	}

	// public static void copyTree(File src, File dst, PathFilter filter) throws
	// IOException {
	// if (!filter.accept(new Path(src.getAbsolutePath()))) {
	// return;
	// }
	// if (src.isFile()) {
	// copyFile(src, dst);
	// } else if (src.isDirectory()) {
	// if (dst.exists()) {
	// dst = new File(dst, src.getName());
	// dst.mkdir();
	// } else { // alow renaming dest dir
	// dst.mkdirs();
	// }
	// File[] files = src.listFiles();
	// for (File file : files) {
	// copyTree(file, dst, filter);
	// }
	// }
	// }

	// /**
	// * Decodes an URL path so that is can be processed as a filename later.
	// *
	// * @param url
	// * the Url to be processed.
	// * @return the decoded path.
	// */
	// public static String getFilePathFromUrl(URL url) {
	// String path = "";
	// if ("file".equals(url.getProtocol())) {
	// try {
	// path = URLDecoder.decode(url.getPath(), "UTF-8");
	// } catch (UnsupportedEncodingException e) {
	// ExceptionUtil.caught(e, "不支持的编码方式");
	// }
	// }
	// return path;
	// }

	// public static File getFileFromURL(URL url) {
	// File file;
	// String filename = getFilePathFromUrl(url);
	// if (StringUtils.isBlank(filename)) {
	// file = null;
	// } else {
	// file = new File(filename);
	// }
	// return file;
	// }

	// /**
	// * Retrieves the total path of a resource from the Thread Context.
	// *
	// * @param resource
	// * the resource name to be retrieved.
	// * @return the decoded path.
	// */
	// public static String getResourcePathFromContext(String resource) {
	// URL url =
	// Thread.currentThread().getContextClassLoader().getResource(resource);
	// return getFilePathFromUrl(url);
	// }
	//
	// public static File getResourceFileFromContext(String resource) {
	// File file;
	// String filename = getResourcePathFromContext(resource);
	// if (StringUtils.isBlank(filename)) {
	// file = null;
	// } else {
	// file = new File(filename);
	// }
	// return file;
	// }

	public static File[] findFiles(File root, String pattern) {
		return findFiles(root, pattern, false);
	}

	public static File[] findFiles(File root, String pattern, boolean recurse) {
		List<File> result = new ArrayList<File>();
		if (null == pattern) {
			if (recurse) {
				collectFiles(root, result);
			} else {
				return root.listFiles();
			}
		} else {
			if (recurse) {
				collectFiles(root, pattern, result);
			} else {
				File[] files = root.listFiles();
				if (files == null || files.length == 0)
					return null;
				for (File file : files) {
					if (wildcardMatch(file.getName().toLowerCase(), pattern)) {
						result.add(file);
					}
				}
			}
		}
		return result.toArray(new File[result.size()]);
	}

	public static void collectFiles(File root, String pattern, List<File> result) {
		File[] files = root.listFiles();
		for (File file : files) {
			if (wildcardMatch(file.getName(), pattern)) {
				result.add(file);
				if (file.isDirectory()) {
					collectFiles(file, pattern, result);
				}
			}
		}
	}

	public static void collectFiles(File root, List<File> result) {
		File[] files = root.listFiles();
		for (File file : files) {
			result.add(file);
			if (file.isDirectory()) {
				collectFiles(root, result);
			}
		}
	}

	// public static boolean matchPattern(String fileName, char[] pattern) {
	// if ("pcf_159902_20161213.xml".equals(fileName)) {
	// System.out.println(fileName);
	// }
	// return matchPattern(fileName.toCharArray(), pattern);
	// }

	// public static boolean matchPattern(char[] name, char[] pattern) {
	// return matchPattern(name, 0, name.length, pattern);
	// }

	// public static boolean matchPattern(char[] name, int offset, int len,
	// char[] pattern) {
	// int i = offset;
	// boolean wildcard = false;
	// for (int j = 0; j < pattern.length; j++) {
	// char c = pattern[j];
	// switch (c) {
	// case '*':
	// wildcard = true;
	// break;
	// case '?':
	// i++;
	// break;
	// default:
	// if (wildcard) {
	// while (i < len) {
	// char na = name[i++];
	// if (na == c) {
	// break;
	// }
	// }
	// if (i == len) {
	// return true;
	// }
	// wildcard = false;
	// } else if (name[i] != c) {
	//
	// } else if (i >= len || name[i] != c) {
	// return false;
	// } else {
	// i++;
	// }
	// break;
	// }
	// }
	// return wildcard || i == len;
	// }

	public static void appendLines(File file, List<String> lines) throws FileNotFoundException {
		PrintWriter out = null;
		try {
			out = new PrintWriter(new FileOutputStream(file, true));
			for (String line : lines) {
				out.println(line);
			}
		} finally {
			if (out != null) {
				out.close();
			}
		}

	}

	/**
	 * 复制文件
	 * 
	 * @param srcPath
	 *            源文件路径包括文件名
	 * @param dstPath
	 *            不包括文件名
	 * @throws IOException
	 */
	public static String copyByStrPath(String srcPath, String dstPath) throws IOException {
		String fileName = srcPath.substring(srcPath.lastIndexOf("\\"), srcPath.length());
		File src = new File(srcPath);
		File dst = new File(dstPath + fileName);
		copy(src, dst);
		return fileName;
	}

	/**
	 * 递归查找文件
	 * 
	 * @param baseDirName
	 *            查找的文件夹路径
	 * @param targetFileName
	 *            需要查找的文件名
	 * @param fileList
	 *            查找到的文件集合
	 */
	public static List<File> findFiles(String baseDirName, String pattern) {
		List<File> fileList = Lists.newArrayList();
		File baseDir = new File(baseDirName); // 创建一个File对象
		if (!baseDir.exists() || !baseDir.isDirectory()) { // 判断目录是否存在
			System.out.println("文件查找失败：" + baseDirName + "不是一个目录！");
		}
		String tempName = null;
		// 判断目录是否存在
		File tempFile;
		File[] files = baseDir.listFiles();
		for (int i = 0; i < files.length; i++) {
			tempFile = files[i];
			if (tempFile.isDirectory()) {
				fileList.addAll(findFiles(tempFile.getAbsolutePath(), pattern));
			} else if (tempFile.isFile()) {
				tempName = tempFile.getName();
				if (wildcardMatch(tempName, pattern)) {
					// 匹配成功，将文件名添加到结果集
					fileList.add(tempFile.getAbsoluteFile());
				}
			}
		}
		return fileList;
	}

	/**
	 * 通配符匹配
	 * 
	 * @param pattern
	 *            通配符模式
	 * @param str
	 *            待匹配的字符串
	 * @return 匹配成功则返回true，否则返回false
	 */
	private static boolean wildcardMatch(String fileName, String pattern) {
		int patternLength = pattern.length();
		int strLength = fileName.length();
		int strIndex = 0;
		char ch;
		for (int patternIndex = 0; patternIndex < patternLength; patternIndex++) {
			ch = pattern.charAt(patternIndex);
			if (ch == '*') {
				// 通配符星号*表示可以匹配任意多个字符
				while (strIndex < strLength) {
					if (wildcardMatch(fileName.substring(strIndex), pattern.substring(patternIndex + 1))) {
						return true;
					}
					strIndex++;
				}
			} else if (ch == '?') {
				// 通配符问号?表示匹配任意一个字符
				strIndex++;
				if (strIndex > strLength) {
					// 表示str中已经没有字符匹配?了。
					return false;
				}
			} else {
				if ((strIndex >= strLength) || (ch != fileName.charAt(strIndex))) {
					return false;
				}
				strIndex++;
			}
		}
		return (strIndex == strLength);
	}

	public static void main(String[] args) {
		File[] files3 = FileUtils.findFiles(new File("E:/新建文件夹"), "*20161213*");
		System.out.println(files3.length);
		for (File f : files3) {
			System.out.println(f.getName());
		}
	}
}